home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 04 - 1988 / 04.03 Mar 88 / Forth Column / Reminder.fth edit < prev   
Encoding:
Text File  |  1988-01-26  |  8.6 KB  |  363 lines  |  [TEXT/EDIT]

  1. \ ***** Time manager example - a 'reminder' utility
  2. \ J. Langowski December 87 
  3. \
  4. \ Strategy: write a driver that sets up a dialog which allows 
  5. \ to enter a time & message to display after that time. After 
  6. \ the appointment has been entered, the driver sets up a 
  7. \ time manager call for that appointment.
  8. \ The time manager routine installs a SystemTask trap patch
  9. \ which at the next occasion will draw an alert box containing
  10. \ the message to be displayed. 
  11. \
  12. \ Note that we have to use the patch rather than calling 
  13. \ the alert routine directly from our time manager task,
  14. \ since we can't be sure we're not in the middle of a 
  15. \ memory manager operation when it is called.
  16. \
  17.  
  18. only forth also assembler also mac
  19.  
  20. CODE InsTime ( tmTaskPtr | -- )
  21.     MOVE.L (A6)+,A0
  22.     _InsTime
  23.     RTS
  24. END-CODE MACH
  25.  
  26. CODE PrimeTime ( tmTaskPtr count | -- )
  27.     MOVE.L (A6)+,D0
  28.     MOVE.L (A6)+,A0
  29.     _PrimeTime
  30.     RTS
  31. END-CODE MACH
  32.  
  33. CODE RmvTime ( tmTaskPtr | -- )
  34.     MOVE.L (A6)+,A0
  35.     _RmvTime
  36.     RTS
  37. END-CODE MACH
  38.  
  39. 4ascii MENU constant "menu
  40. 4ascii PROC constant "proc
  41.  
  42. \ *** compiler support words for external definitions *** 
  43. : :xdef 
  44.     create     -4 allot
  45.         $4EFA w, ( JMP )
  46.         0 w,     ( entry point to be filled later )
  47.         0 ,      ( length of routine to be filled later )
  48.         here 6 - 76543
  49. ;
  50.  
  51. : ;xdef { branch marker entry | -- }
  52.     marker 76543 <> abort" xdef mismatch"
  53.     entry branch - branch w!
  54.     here branch - 2+ branch 2+ !
  55.     
  56. : xlen 4 + @ ; ( get length word of external definition )
  57.  
  58. ( *** driver header block *** )
  59.  
  60.  0 CONSTANT drvrFlags
  61.  2 CONSTANT drvrdelay 
  62.  4 CONSTANT drvrEMask
  63.  6 CONSTANT drvrMenu
  64.  8 CONSTANT drvrOpen
  65. 10 CONSTANT drvrPrime
  66. 12 CONSTANT drvrCtl
  67. 14 CONSTANT drvrStatus
  68. 16 CONSTANT drvrClose
  69. 18 CONSTANT drvrname
  70. 50 CONSTANT DAlength
  71.  
  72. \ *** compiler support words for DA and driver definitions ***
  73. : :DA 
  74.     create     -4 allot
  75.         here 87654 ( start of DA block, and marker )
  76.         50 allot   ( length of block )
  77. ;
  78.  
  79. : ;DA { DAstart marker Ropen Rprime Rctl Rstatus Rclose
  80.         Rflags Rdelay Remask Rmenu Rname | -- }
  81.     marker 87654 <> abort" DA definition mismatch"
  82.     Ropen     DAStart - DAStart drvrOpen + w!
  83.     Rprime     DAStart - DAStart drvrPrime + w!
  84.     Rctl         DAStart - DAStart drvrCtl + w!
  85.     Rstatus     DAStart - DAStart drvrStatus + w!
  86.     Rclose     DAStart - DAStart drvrClose + w!
  87.     Rflags          DAStart drvrFlags + w!
  88.     Rdelay          DAStart drvrDelay + w!
  89.     Remask          DAStart drvrEmask + w!
  90.     RMenu              DAStart drvrMenu + w!
  91.     Rname count dup      DAStart drvrName + c!
  92.         DAStart drvrName + 1+ swap 
  93.         dup 31 > if drop 31 then cmove 
  94.     here DAstart -       DAStart DAlength + !
  95.     
  96. : DAlen DAlength + @ ; ( get length word of external definition )
  97.  
  98. \ **** DA glue macros
  99.  
  100. CODE DA.prelude
  101.     LINK    A6,#-512        \ 512 bytes of local Forth stack
  102.     MOVEM.L     A0-A1,-(A7)    \ save registers
  103.     MOVE.L      A6,A3        \ setup local loop return stack
  104.     SUBA.L   #256,A3         \ in the low 256 local stack bytes
  105.     MOVE.L      A0,-(A6)     \ parameter block
  106.     MOVE.L      A1,-(A6)    \ device control entry
  107.     RTS                        \ just to indicate the MACHro stops here 
  108. END-CODE MACH
  109.  
  110. CODE DA.epilogue
  111.     MOVE.L      (A6)+,D0    \ return code
  112.     MOVEM.L     (A7)+,A0-A1    \ restore registers
  113.     UNLK        A6
  114.     RTS
  115. END-CODE MACH
  116.  
  117. CODE DA.Jiodone
  118.     MOVE.L      (A6)+,D0    \ return code
  119.     MOVEM.L     (A7)+,A0-A1    \ restore registers
  120.     UNLK        A6
  121.     move.l        JIODone,A0
  122.     movem.l     d4-d7/a4-a6,-(a7)
  123.     jsr            (a0)
  124.     movem.l    (a7)+,d4-d7/a4-a6
  125.     RTS
  126. END-CODE MACH
  127.  
  128. .TRAP    _newptr,sys    $A51E
  129.  
  130. %0000000101001010 CONSTANT DAEmask
  131.  
  132. $1B4 CONSTANT SystemTask
  133.  
  134. \ __________________________________________________
  135. \ time manager and systemTask patch routine
  136. \ this routine must reside in a block allocated 
  137. \ in the system heap through a pointer. 
  138. \ __________________________________________________
  139.  
  140. header myTask 14 allot
  141. 6 CONSTANT taskPtr
  142. HEADER myName
  143.     DC.B     9,0,'Reminder'
  144. header myTrap 4 allot
  145. header myAlert 4 allot
  146. header myString 256 allot
  147.  
  148. : alertMe 
  149.     MOVEM.L    A0-A4/A6/D0-D7,-(A7)
  150.     LINK    A6,#-128    \ 128 bytes of local Forth stack
  151.     (call) frontwindow windowkind + @
  152.     2 <> IF
  153.         ['] myTrap @ SystemTask (call) SetTrapAddress
  154.         ['] myString 0 0 0 (call) paramText
  155.         ['] myAlert @ 0 (call) noteAlert drop
  156.         ['] myAlert @ (call) freeAlert
  157.         ['] myTask RmvTime
  158.         ['] myTask (call) DisposPtr drop
  159.     THEN
  160.     UNLK    A6
  161.     MOVEM.L    (A7)+,A0-A4/A6/D0-D7
  162. ;
  163.  
  164. : wakeMe
  165.     SystemTask (call) GetTrapAddr ['] myTrap !
  166.     ['] alertMe SystemTask (call) SetTrapAddr
  167. ;
  168.  
  169. header mytask.end
  170. ' wakeme ' mytask - CONSTANT *wakeme \ task offset
  171. ' myAlert ' mytask - CONSTANT *myAlert \ alertID 
  172. ' myString ' mytask - CONSTANT *myString \ alert string
  173.  
  174. \ ___________________________________________
  175. \ desk accessory code starts here.
  176. \ ___________________________________________
  177.  
  178. :DA reminder 
  179.     .ALIGN
  180.  
  181. ( *** main desk accessory routines *** )
  182. header myRes0 4 allot        \ local res ID=0 offset 
  183. header dlgText 256 allot
  184.  
  185. \ redefinition of cmove to make it 
  186. \ available locally
  187.  
  188. CODE cmove
  189.     move.l    (a6)+,d0
  190.     move.l    (a6)+,a1
  191.     move.l    (a6)+,a0
  192.     tst.l    d0
  193.     ble.s    @2
  194. @1    move.b    (a0)+,(a1)+
  195.     subq.l    #1,d0
  196.     bne.s    @1
  197. @2    rts
  198. END-CODE
  199.  
  200. \ ___________________
  201. \ wakeup routine installation
  202. \ ___________________
  203.  
  204. : install.wakeup 
  205.     { delay alrtID msg | procHdl hSize taskBlock -- }
  206.  
  207.     "proc ['] myRes0 @ (call) GetResource -> procHdl
  208.     procHdl (call) getHandleSize -> hSize
  209.         hSize MOVE.L (A6)+,D0
  210.         _newPtr,sys
  211.         MOVE.L    A0,-(A6) -> taskBlock
  212.     procHdl @ taskBlock hSize cmove
  213.     procHdl (call) releaseResource
  214.         \ we have made a local copy of the wakeup routine
  215.     taskBlock dup *wakeMe + swap taskPtr + !
  216.         msg taskBlock *myString + 256 cmove
  217.         alrtID taskBlock *myAlert + !
  218.         alrtID (call) CouldAlert
  219.     taskBlock InsTime
  220.     taskBlock delay PrimeTime
  221.         \ now the wakeup routine will wake up after
  222.         \ the scheduled delay.
  223. ;
  224.  
  225. : getDrvrID { dCtlEntry | -- num }
  226.     dCtlEntry dCtlRefNum + w@ l_ext
  227.     1+ negate
  228. ;
  229.  
  230. : ownResID ( resID drvrID )
  231.     5 shl + -16384 +
  232. ;
  233.  
  234. : Open { parblk dce | DAWind Res0 -- returncode }
  235.     5 (call) sysbeep 
  236.         \ to get attention if automatically opened
  237.     0 dce getDrvrID ownResID -> Res0
  238.     dce dCtlWindow + @ -> DAWind
  239.     DAWind 0= IF ( not open already )
  240.         Res0 ['] myRes0 !
  241.         Res0 0 -1 (call) getNewDialog -> DAWind
  242.         DAWind  dce dCtlWindow + !  \ store dialog pointer
  243.         DAWind  dce dCtlRefNum + w@  swap windowKind + w!
  244.     ELSE
  245.         DAWind (call) selectWindow
  246.     THEN
  247.     0
  248. ;
  249.  
  250. : Close { parblk dce | -- returncode }
  251.     dce dCtlWindow + 
  252.     dup @ (call) DisposDialog  
  253.         0 swap ! ( so that Open will work again )
  254.     0
  255. ;
  256.  
  257. : dialog-handler 
  258.     { dlgPtr itemHit | 
  259.         itemType hItem rBox seconds -- }
  260.  
  261. \ we get here if the OK button in the dialog
  262. \ has been hit, therefore itemHit is always =1 
  263. \ - in our case. But it is nice to have itemHit
  264. \ available, to be more general. 
  265. \ item #3 contains the appointment message
  266. \ item #4 contains the delay in seconds
  267. \ (decimal number string)
  268.  
  269.     dlgPtr 4 ^ itemType ^ hItem ^ rBox (call) GetDItem
  270.     hItem ['] dlgText (call) GetIText
  271.     ['] dlgText (call) StringToNum -> seconds
  272.     seconds 0> IF
  273.         dlgPtr 3 ^ itemType ^ hItem ^ rBox 
  274.                             (call) GetDItem
  275.         hItem ['] dlgText (call) GetIText
  276.         seconds 1000 w* 
  277.             ['] myres0 @ ['] dlgText install.wakeup        
  278.         ELSE 10 (call) sysbeep
  279.         THEN
  280. ;
  281.  
  282. : Ctl { parblk dce | DAWind event-rec dlgPtr itemHit -- returncode }
  283.     
  284.     dce dCtlWindow + @ -> DAWind
  285.  
  286.     parblk csCode + w@ l_ext 
  287.     CASE
  288.         accEvent OF
  289.             2 DAWind windowKind + w! \ set to dialog window 
  290.             parblk csParam + @ -> event-rec
  291.             event-rec (call) IsDialogEvent
  292.             IF  event-rec ^ dlgPtr ^ itemHit
  293.                 (call) Dialogselect
  294.                 IF dlgPtr itemHit dialog-handler THEN
  295.             THEN
  296.             DAWind  dce dCtlRefNum + w@  
  297.                 swap windowKind + w! \ reset windowkind
  298.         ENDOF
  299.  
  300.     ENDCASE
  301.     0
  302. ;
  303.  
  304.  
  305. : DrOpen DA.Prelude Open DA.Epilogue ;
  306. : DrClose DA.Prelude Close DA.Epilogue ;
  307. : DrCtl DA.Prelude Ctl DA.JioDone ;
  308. : DrStatus ;
  309. : DrPrime ;
  310.  
  311. ' DrOpen ' DrPrime ' DrCtl ' DrStatus ' DrClose
  312. $7400 \ need lock, need time, need goodbye, ctl calls
  313. 60 DAEmask 0 \ delay mask menu
  314. " Reminder" \ name
  315. ;DA
  316.  
  317.  
  318. ( write resource to file ) 
  319. : $create-res ( str-addr - errcode )
  320.     call CreateResFile
  321.     call ResError L_ext
  322. ;
  323.  
  324. : $open-res { addr | refNum - refNum or errcode }
  325.     addr call OpenResFile -> refNum
  326.     call ResError L_ext
  327.     ?dup IF ELSE refNum THEN
  328.  
  329. : close-res ( refNum - errcode )
  330.     call CloseResFile
  331.     call ResError L_ext
  332. ;
  333.  
  334. : make-res { addr len rtype ID name | -- }
  335.     addr len call PtrToHand 
  336.     abort" Could not create resource handle"
  337.     rtype ID name call AddResource
  338. ;
  339.  
  340. : write-out { filename | refnum -- } 
  341.     filename $create-res abort" That resource file already exists"
  342.     filename $open-res
  343.     dup 0< abort" Open resource file failed"
  344.     -> refnum
  345.     refnum call UseResFile
  346.     ['] reminder dup DALen
  347.         "drvr 12 " Reminder" make-res
  348.     ['] myTask ['] mytask.end over - 
  349.         "proc -16000 " wakeUp" make-res
  350.         "proc -16000 call GetResource
  351.         dup 80 call SetResAttrs  ( 64: sysheap + 16: locked )
  352.         call ChangedResource
  353.     refnum close-res abort" Could not close resource file"
  354. ;
  355.  
  356. : make-DA
  357.     " Reminder.rsrc" $delete drop
  358.     " Reminder.rsrc" write-out
  359. ;
  360.